package com.platform.jpa.dao.impl;

import java.lang.reflect.Constructor;

import javax.persistence.EntityManager;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;

public class BaseDaoFactoryBean <R extends JpaRepository<T, ID>, T, ID> extends JpaRepositoryFactoryBean<R, T, ID>  {
    public BaseDaoFactoryBean(Class<? extends R> repositoryInterface) {
        super(repositoryInterface);
    }

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(final EntityManager entityManager) {
        return new JpaRepositoryFactory(entityManager) {

            protected SimpleJpaRepository<T, ID> getTargetRepository(
                    RepositoryInformation information, EntityManager entityManager) {
                Class<T> domainClass = (Class<T>) information.getDomainType();
                try {
                    Class cls = information.getRepositoryBaseClass();
                    Constructor c1 = cls.getDeclaredConstructor(Class.class, EntityManager.class);
                    return (SimpleJpaRepository)c1.newInstance(domainClass, entityManager);
                }  catch (Exception e) {
                    return null;
                }
            }

            @Override
            protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata){
                String iName = metadata.getRepositoryInterface().getSimpleName();
                String iPackage = metadata.getRepositoryInterface().getPackage().getName();
                try {
                    String implName = iPackage + ".impl." + (iName.startsWith("I") ? iName.substring(1) : iName)  + "Impl";
                    return Class.forName(implName);
                } catch (ClassNotFoundException cnfe) {
                    return BaseDaoImpl.class;
                } catch (Exception e) {
                    return null;
                }
            }
        };
    }
}
